AMDGPU: add hotswap entry trampoline core#3008
Conversation
3c42707 to
c3065ae
Compare
e8897c6 to
280c69b
Compare
280c69b to
737534a
Compare
737534a to
1de7a53
Compare
| const llvm::StringRef Expected[] = {"v_mbcnt_lo_u32_b32", | ||
| "v_mbcnt_hi_u32_b32", | ||
| "v_lshlrev_b32", | ||
| "v_add_nc_u32", | ||
| "v_and_b32", | ||
| "ds_store_b32", | ||
| "s_branch"}; |
There was a problem hiding this comment.
This is an improvement, but it feels rather incomplete if we dont check the operands of the rewritten instructions.
We should definitely have integration tests, but IMO it should also be fixed in Unit tests.
There was a problem hiding this comment.
Fixed. Unit tests now compare decoded MCInst operands against expected assembled instructions for ADDTID load/store bodies and the entry trampoline.
| // RUN: %clang -target amdgcn-amd-amdhsa -mcpu=gfx1250 -nostdlib %s -o %t.elf | ||
|
|
||
| // RUN: AMD_COMGR_HOTSWAP_ENTRY_TRAMPOLINES=1 hotswap-rewrite %t.elf \ | ||
| // RUN: amdgcn-amd-amdhsa--gfx1250 amdgcn-amd-amdhsa--gfx1250 \ |
There was a problem hiding this comment.
This style of the triple is going to be deprecated soon. But I suppose we will take of it after that change flows in Comgr from upstream...
There was a problem hiding this comment.
This style of the triple is going to be deprecated soon.
This is news to me. What is it going to be moving forward?
But I suppose we will take of it after that change flows in Comgr from upstream...
Thank you :)
There was a problem hiding this comment.
You can refer to the PR stack here to get a clue : https://github.com/llvm/llvm-project/pull/206488/changes.
I am trying to get a hold of the presentation that Matt gave to the compiler team yesterday. I'll share it with others when I have it.
Effectively, moving towards:
amdgpu12.50-amd-amdhsa
|
I have read through the code generally, but admittedly, there's a lot of it. I'm sure to have missed things. I ran it through Claude and here are some issues that we should probably take a look at:
AFAICT, these are really corner cases that we probably wont encounter in well-formed kernels. In that sense, I think we should be okay. |
1de7a53 to
2ef5a67
Compare
Thanks. I fixed the entry-trampoline issues from this list: opcode-only idempotency, vaddr alignment, program-header overflow, entryVAddr idempotency failure, and missing operand checks in unit tests. I left the debug/metadata/symbol-order/duplicate-name items unchanged since they are broader ELF/debug/metadata policy issues outside this PR’s entry-trampoline path. |
7eb0c18 to
bcd7a3e
Compare
bcd7a3e to
f357644
Compare
|
Also I modified this PR so comgr no longer depends on the global environment var. The idea is that rocr runtime will call comgr with the appropriate rewrite options depending on the value of that global environment var. The existing amd_comgr_hotswap_rewrite path remains ABI-compatible and keeps entry trampolines off by default, while callers like rocm-systems can opt in only for the gfx12.5 cases they own using amd_comgr_hotswap_rewrite_with_options. |
I see, thanks. Yes, I think thats the right thing to do. However, the LIT test (and its driver) does not exercise the new path yet. |
|
Done. I moved the minimal public LIT coverage into this PR so #3008 now exercises the new options API directly. The shared Verified normal and ASAN hotswap lit: 53 tests passed in each build. |
| if (!Options.RunB0A0Patches && !Options.RunEntryTrampolines) { | ||
| std::unique_ptr<WritableMemoryBuffer> Result = | ||
| WritableMemoryBuffer::getNewUninitMemBuffer(ElfSize); | ||
| if (!Result) { | ||
| log() << "hotswap: error: retargetCodeObject: " | ||
| << "getNewUninitMemBuffer(" << ElfSize | ||
| << ") failed (out of memory) for the no-op output copy.\n"; | ||
| return AMD_COMGR_STATUS_ERROR_OUT_OF_RESOURCES; | ||
| } | ||
| std::memcpy(Result->getBufferStart(), ElfData, ElfSize); | ||
| Out = std::move(Result); | ||
| return AMD_COMGR_STATUS_SUCCESS; | ||
| } |
There was a problem hiding this comment.
I think we're almost there.
This no-op behavior should be documented somewhere
There was a problem hiding this comment.
Its also weird that there's no way for the caller to know whether this was exercised.
There was a problem hiding this comment.
I agree this is not ideal, but I would prefer not to grow the API shape in this PR. For now, callers that need to know can compare input/output bytes. If ROCr needs structured pass-result reporting, we should add that as a follow-up API extension.
There was a problem hiding this comment.
Done. I documented this in the public hotswap API comments and the HotSwap README. SUCCESS means comgr produced a valid output code object, not that bytes necessarily changed; if source/target/options select no enabled rewrite, output is a copy of the input.
| /// amd_comgr_hotswap_rewrite, and optionally dumps the output and/or checks | ||
| /// that a second rewrite produces identical output (idempotency). | ||
| /// the hotswap rewrite API, and optionally dumps the output and/or checks that | ||
| /// a second rewrite produces identical output (idempotency). |
There was a problem hiding this comment.
Do we need to claim idempotency? This is a strong claim and I wonder if we have tests for it.
When B0A0 and entry trampolines run together, the B0-to-A0 pass re-decodes the whole grown .text (now including the appended stub pool) and has no 'skip existing stub' guard, unlike the entry pass (Work-empty check).
There was a problem hiding this comment.
Agreed. I reworded the driver comment. The intent is only that the test driver can rerun the same request and compare outputs, not to claim global idempotency for every combination of rewrite options.
|
There's also a bunch of redundancy in implementation, but we can take that up in the refactor. |
|
Sounds good. I will leave the broader cleanup for the follow-up refactor and keep this PR focused on the API and entry-trampoline behavior. |
|
Thanks. This mostly LGTM. @lamb-j is planning to look as well, so I'd recommend we wait for his inputs. |
Sounds good. Can we land this and address his comments in the follow up PR? |
|
Sure. When I had a chat with him, I think a concern was about adding a new Comgr API without incrementing the semantic versioning. Although, in this case I dont think that would be an issue. Its okay to land for now. |
|
Filed #3134 Ideally in the future, we do the version bump in the same commit as the API introduction. It's easier to cherry-pick, revert, etc. if they're together. Also if we're really unlucky, a branch can be cut between the API introduction and the version bump, which exposes us to some pretty big inconsistencies. Not as big a deal for minor bumps compared to major, but still not ideal |
## Summary Adds an explicit API-versioning rule to `amd/comgr/AGENT_CONVENTIONS.md` (section 4, PR workflow): every commit that adds a public `AMD_COMGR_API` function must bump the minor version in `VERSION.txt` and tag the new prototype with a fresh `AMD_COMGR_VERSION_X_Y` macro. This codifies the policy that surfaced when #3008 added `amd_comgr_hotswap_rewrite_with_options` under the already-used `3.3` version without bumping (fixed in its follow-up #3134). The rule captures: - One bump per commit, not per function. - Never reuse the current version's macro for a new API in a later commit. - Don't wait for an official release to bump — we don't know which commit lands in each release, so the version advances when the API is introduced. - Add the symbol to `exportmap.in` under a version node matching the new tag. - `check_api_consistency.py` only enforces `VERSION.txt >=` the highest macro, so it cannot catch version reuse — verify the bump by hand. ## Changes - `AGENT_CONVENTIONS.md`: add the "Bump the version when adding a public API" subsection.
#3134) ## Summary Follow-up to #3008, which added the `amd_comgr_hotswap_rewrite_with_options` API but tagged it `AMD_COMGR_VERSION_3_3` — a version already consumed by the block-size kernel APIs in #1946. Per our policy, every commit that adds a new public API must also bump the minor version, so the hotswap options API should own its own version. The `check_api_consistency.py` script only enforces `VERSION.txt >=` the highest tag macro, so the duplicate `3.3` tag passed CI even though it reused an existing version. ## Changes - `VERSION.txt`: bump minor `3` -> `4`. - `amd_comgr.h.in`: add the `AMD_COMGR_VERSION_3_4` macro and retag `amd_comgr_hotswap_rewrite_with_options` from `3.3` to `3.4`. - `exportmap.in`: move `amd_comgr_hotswap_rewrite_with_options` into a new `@amd_comgr_NAME@_3.4` symbol-version node inheriting from `_3.3`. The symbol-version change is safe: `3.3` has not shipped in a release, so no external consumer depends on the `@_3.3` versioned symbol. `python3 amd/comgr/utils/check_api_consistency.py --comgr-dir amd/comgr` passes (`VERSION.txt=3.4`, 69 APIs declared and exported).
## JIRA ID JIRA ID - ROCM-27304 ## Stack Layer 2 of the rocm-systems HotSwap stack, paired with ROCm/llvm-project#3008. - Previous layer: #7577 - This layer: rocm-systems loader gating and COMGR request selection for the gfx12.5 entry-trampoline path - Final layer: #7592 ## Summary - Keep rocm-systems limited to loader routing and COMGR source/target ISA-pair construction; COMGR owns validation and all code-object transformations after the call. - Use ROCm/llvm-project#3008's explicit COMGR options API: ROCr calls `amd_comgr_hotswap_rewrite_with_options` with `AMD_COMGR_HOTSWAP_REWRITE_FLAG_ENTRY_TRAMPOLINES` when it requests entry trampolines, and keeps `amd_comgr_hotswap_rewrite` for legacy/default rewrites. - Keep `AMD_COMGR_HOTSWAP_ENTRY_TRAMPOLINES` as the ROCr policy knob: default enabled in ROCr, literal `0` disables, unset/empty/any other value enables the entry-trampoline request. - Cover concrete `gfx125*` targets and `gfx12-5-generic` while keeping non-gfx12.5 agents and source code objects unchanged. - Follow #7581 by keeping the entry-trampoline path keyed to the code-object ISA rather than using this path for processor retargeting. - Preserve the existing gfx1250 A0 source/target ISA pair and leave pass selection to COMGR. - Add unit and loader-path coverage for the local routing behavior without testing COMGR pass internals. ## Testing - `git diff --check` - `cmake --build build-rocrtst-hotswap-review --target hotswap_rewrite -j 8` - `ctest --test-dir build-rocrtst-hotswap-review -R hotswap --output-on-failure` - `cmake --build build-rocr-hotswap --target hsa-runtime64 -j 8`
Stack:
The temporary ROCm base branch users/harsh/comgr-hotswap-entry-core mirrors this PR head so #3098 shows only the incremental LIT diff.
Summary:
amd_comgr_hotswap_rewrite_with_optionsandAMD_COMGR_HOTSWAP_REWRITE_FLAG_ENTRY_TRAMPOLINESso callers request entry trampolines explicitly per rewrite call.AMD_COMGR_HOTSWAP_ENTRY_TRAMPOLINES; COMGR no longer uses that env var as the integration contract.amd_comgr_hotswap_rewriteABI-compatible default path without entry trampolines.hotswap-rewriteLIT driver to exerciseamd_comgr_hotswap_rewrite_with_options.Verification:
python3 amd/comgr/utils/check_api_consistency.py --comgr-dir amd/comgrpassed.cmake --build build --target hotswap-rewrite -- -j8passed.build/bin/llvm-lit -sv build/tools/comgr/test-lit --filter 'hotswap-rewrite.c|hotswap-kernel-entry-trampoline.s'passed: 2 tests on AMDGPU: add hotswap entry trampoline core #3008.build/bin/llvm-lit -sv build/tools/comgr/test-lit --filter hotswappassed: 53 tests on the stack top.cmake --build build-asan --target hotswap-rewrite -- -j8passed.build-asan/bin/llvm-lit -sv build-asan/tools/comgr/test-lit --filter hotswappassed: 53 tests on the stack top.check-comgrpassed after the options API update: lit 72 passed/11 unsupported; unit tests passed; CTest 31/31 passed.check-comgrpassed after the options API update: lit 72 passed/11 unsupported; unit tests passed; CTest 31/31 passed.